// Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
// Copyright (C) 2002 Microsoft Corporation
// All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
// OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
//
// Date    - 10/08/2002
// Author  - Sanj Surati

/////////////////////////////////////////////////////////////
//
// SPNEGOPARSE.H
//
// SPNEGO Token Parser Header File
//
// Contains the definitions required to properly parse a
// SPNEGO token using ASN.1 DER helpers.
//
/////////////////////////////////////////////////////////////

#ifndef __SPNEGOPARSE_H__
#define __SPNEGOPARSE_H__

// C++ Specific
#if defined(__cplusplus)
extern "C"
{
#endif

// Indicates if we copy data when creating a SPNEGO_TOKEN structure or not
#define SPNEGO_TOKEN_INTERNAL_COPYPTR           0
#define SPNEGO_TOKEN_INTERNAL_COPYDATA          0x1

// Internal flag dictates whether or not we will free the binary data when
// the SPNEG_TOKEN structure is destroyed
#define  SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA   0x1

   //
// Each SPNEGO Token Type can be broken down into a
// maximum of 4 separate elements.
//

#define  MAX_NUM_TOKEN_ELEMENTS  4

//
// Element offsets in the array
//

// INIT elements
#define  SPNEGO_INIT_MECHTYPES_ELEMENT    0
#define  SPNEGO_INIT_REQFLAGS_ELEMENT     1
#define  SPNEGO_INIT_MECHTOKEN_ELEMENT    2
#define  SPNEGO_INIT_MECHLISTMIC_ELEMENT  3

// Response elements
#define  SPNEGO_TARG_NEGRESULT_ELEMENT    0
#define  SPNEGO_TARG_SUPPMECH_ELEMENT     1
#define  SPNEGO_TARG_RESPTOKEN_ELEMENT    2
#define  SPNEGO_TARG_MECHLISTMIC_ELEMENT  3

//
// Defines an individual SPNEGO Token Element.
//

typedef struct SpnegoElement
{
   size_t                nStructSize;        // Size of the element structure
   int                   iElementPresent;    // Is the field present?  Must be either
                                             // SPNEGO_TOKEN_ELEMENT_UNAVAILABLE or
                                             // SPNEGO_TOKEN_ELEMENT_AVAILABLE

   SPNEGO_ELEMENT_TYPE   eElementType;       // The Element Type

   unsigned char         type;               // Data Type

   unsigned char*        pbData;             // Points to actual Data

   unsigned long         nDatalength;        // Actual Data Length

} SPNEGO_ELEMENT;

// Structure size in case we later choose to extend the structure
#define  SPNEGO_ELEMENT_SIZE sizeof(SPNEGO_ELEMENT)

//
// Packages a SPNEGO Token Encoding.  There are two types of
// encodings: NegTokenInit and NegTokenTarg.  Each encoding can
// contain up to four distinct, optional elements.
//

typedef struct SpnegoToken
{
   size_t            nStructSize;                              // Size of the Token structure
   unsigned long     ulFlags;                                  // Internal Structure Flags - Reserved!
   int               ucTokenType;                              // Token Type - Must be
                                                               // SPNEGO_TOKEN_INIT or
                                                               // SPNEGO_TOKEN_TARG

   unsigned char*    pbBinaryData;                             // Points to binary token data

   unsigned long     ulBinaryDataLen;                          // Length of the actual binary data
   int               nNumElements;                             // Number of elements
   SPNEGO_ELEMENT    aElementArray [MAX_NUM_TOKEN_ELEMENTS];   // Holds the elements for the token
} SPNEGO_TOKEN;

// Structure size in case we later choose to extend the structure
#define  SPNEGO_TOKEN_SIZE sizeof(SPNEGO_TOKEN)

//
// Function definitions
//

SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags,
                                    unsigned char * pbTokenData, unsigned long ulTokenSize );
void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken );
void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken );
int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength,
                           long* pnRemainingTokenLength, unsigned char** ppbFirstElement );
int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData,
                           long nRemainingTokenLength  );
int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength,
                                 SPNEGO_ELEMENT* pSpnegoElement );
int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength,
                                          unsigned char ucExpectedType,
                                          SPNEGO_ELEMENT_TYPE spnegoElementType,
                                          SPNEGO_ELEMENT* pSpnegoElement );
int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength,
                                   SPNEGO_ELEMENT_TYPE spnegoElementType,
                                   SPNEGO_ELEMENT* pSpnegoElement );
int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID,
                           int * piMechTypeIndex );
int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength );
int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, long nMechListMICLength,
         SPNEGO_MECH_OID *mechOid, int mechOidCnt, int nReqFlagsAvailable,
                                    long* plTokenSize, long* plInternalLength );
int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType, SPNEGO_NEGRESULT spnegoNegResult,
                                    long nMechTokenLen,
                                    long nMechTokenMIC, long* pnTokenSize,
                                    long* pnInternalTokenLength );
int CreateSpnegoInitToken( SPNEGO_MECH_OID *MechTypeList, long nMechTypes,
          unsigned char ucContextFlags, unsigned char* pbMechToken,
          unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
          unsigned long ulMechListMICLen, unsigned char* pbTokenData,
          long nTokenLength, long nInternalTokenLength );
int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType,
          SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken,
          unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
          unsigned long ulMechListMICLen, unsigned char* pbTokenData,
          long nTokenLength, long nInternalTokenLength );
int IsValidMechOid( SPNEGO_MECH_OID mechOid );
int IsValidContextFlags( unsigned char ucContextFlags );
int IsValidNegResult( SPNEGO_NEGRESULT negResult );
int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken );
int IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement );
int CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement );
int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags,
                        unsigned char* pbTokenData, unsigned long ulLength,
                        SPNEGO_TOKEN** ppSpnegoToken );

   // C++ Specific
#if defined(__cplusplus)
}
#endif

#endif
